#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <include/cstl.h>

typedef struct my_obj
{
    int* var_a;
    double* var_b;
} my_obj_t;

void my_obj_init(IN const void* dst, OUT void* out)
{
    my_obj_t* obj = (my_obj_t*)(dst);
    obj->var_a = cc_malloc(sizeof(int));
    obj->var_b = cc_malloc(sizeof(double));
    *(obj->var_a) = 112233;
    *(obj->var_b) = 112.233;
}

void my_obj_copy(IN const void* dst, IN const void* src, OUT void* out)
{
    my_obj_t* obj_dst = (my_obj_t*)(dst);
    my_obj_t* obj_src = (my_obj_t*)(src);

    *(obj_dst->var_a) = *(obj_src->var_a);
    *(obj_dst->var_b) = *(obj_src->var_b);
}

void my_obj_compare(IN const void* left, IN const void* right, OUT void* out)
{
    my_obj_t* obj_left = (my_obj_t*)left;
    my_obj_t* obj_right = (my_obj_t*)(right);
    if (*(obj_left->var_a) < *(obj_right->var_a) )
    {
        *(int*)(out) = 1;
    }
    else if (*(obj_left->var_a) > *(obj_right->var_a))
    {
        *(int*)(out) = 0;
    }
    else
    {
        *(int*)(out) = (*(obj_left->var_b) < *(obj_right->var_b));
    }
}

void my_obj_detroy(IN const void* dst, OUT void* out)
{
    my_obj_t* obj_dst = (my_obj_t*)(dst);
    cstl_free(obj_dst->var_a);
    cstl_free(obj_dst->var_b);
}

void print_vector(vector_t vec)
{
    my_obj_t* obj_tmp = NULL;
    size_t index = 0;
    printf("size: %d\n", vector_size(vec));
    printf("capacity: %d\n", vector_capacity(vec));
    printf("content:\n");
    for (index = 0; index < vector_size(vec); ++index)
    {
        obj_tmp = (my_obj_t*)vector_get_entry(vec, index);
        printf("\t[%d], %d, %f\n", index, *obj_tmp->var_a, *obj_tmp->var_b);
    }
    printf("\n\n");
}

int main()
{
    my_obj_t tmp;
    my_obj_t* obj_tmp = NULL;
    int index = 0;
    type_register(my_obj_t, my_obj_init, my_obj_copy, my_obj_compare, my_obj_detroy);

    vector_t vec = vector_create(my_obj_t);

    /**
    * Memory leak.
    */
    if (NULL == vec)
    {
        fprintf(stderr, "create vector failed!\n");
    }
    else
    {
        vector_destroy(vec);
    }

    // printf("Memory leak %lu\n", cstl_memory_leak());

    /*
    *
    */
    tmp.var_a = cstl_malloc(sizeof(int));
    tmp.var_b = cstl_malloc(sizeof(double));
    *tmp.var_a = 11;
    *tmp.var_b = 12.0;

    if (0)
    {
        vec = vector_create(my_obj_t);

        /* capacity test */
        if (0)
        {
            printf("#Before reserve\n");
            print_vector(vec);
            vector_reserve(vec, 10);
            vector_reserve(vec, 12);
            printf("#After reserve\n");
            print_vector(vec);
        }

        /* size test */
        if (0)
        {
            printf("#Test size, before insert\n");
            print_vector(vec);
            vector_insert(vec, 0, &tmp);
            printf("#Test size, after insert\n");
            print_vector(vec);
        }

        /* insert test */
        if (0)
        {
            printf("#Before insert\n");
            print_vector(vec);

            // inset 12, 13.0 at tail
            *tmp.var_a = 12;
            *tmp.var_b = 13.0;
            index = vector_insert(vec, 100, &tmp);
            obj_tmp = (my_obj_t*)vector_get_entry(vec, index);
            printf("#The inserted variable is [%d], %d, %f\n", index, *obj_tmp->var_a, *obj_tmp->var_b);

            // inset 13, 14.0 at head
            *tmp.var_a = 13;
            *tmp.var_b = 14.0;
            index = vector_insert(vec, 0, &tmp);
            obj_tmp = (my_obj_t*)vector_get_entry(vec, index);
            printf("#The insert variable is [%d], %d, %f\n", index, *obj_tmp->var_a, *obj_tmp->var_b);

            printf("#After insert:\n");
            print_vector(vec);
        }

        /* erase test */
        if (0)
        {
            printf("#Before erase the vector size is %d, content is: \n", vector_size(vec));
            vector_erase(vec, 10);
            print_vector(vec);

            vector_erase(vec, 0);
            print_vector(vec);


            vector_erase(vec, 0);
            print_vector(vec);

            vector_erase(vec, 0);
            print_vector(vec);
        }


        /* pop back test */
        if (0)
        {
            printf("Pop back test\n");
            vector_pop_back(vec);
            print_vector(vec);
            vector_pop_back(vec);
            print_vector(vec);
            vector_pop_back(vec);
            print_vector(vec);
        }

        vector_destroy(vec);
        // printf("Memory leak %lu\n", cstl_memory_leak());
    }

    cstl_free(tmp.var_a);
    cstl_free(tmp.var_b);
    
    cstl_exit();
    return 0;
}
